package com.xiaoxi.exam.spring.error;

import cn.xinzhili.xutils.core.ErrorCode;
import cn.xinzhili.xutils.core.FailureException;
import cn.xinzhili.xutils.core.SystemException;
import cn.xinzhili.xutils.core.http.Response;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

/**
 * 集中的Exception拦截, 处理代码中抛出的<code>FailureException</code>和 <code>SystemException</code>
 */
@ControllerAdvice
public class ExceptionResolver {

  private static final Logger logger = LoggerFactory
      .getLogger(ExceptionResolver.class);

  @SuppressWarnings("unchecked")
  @ExceptionHandler(FailureException.class)
  public Object handleFailure(FailureException e, HttpServletRequest request) {
    logger.warn("请求失败 - {}: {}", e.getClass(), e.getMessage());
    if (userAgentAcceptsHtml(request)) {
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName("error");
      modelAndView.addObject("message", "请求失败：" + e.getMessage());
      return modelAndView;
    } else {
      return ResponseEntity.ok(Response.instanceFail(e.getCode()).withData(e.getErrorData()));
    }
  }

  @SuppressWarnings("unchecked")
  @ExceptionHandler(SystemException.class)
  public Object handleError(SystemException e, HttpServletRequest request) {
    logger.error("服务异常", e);
    if (userAgentAcceptsHtml(request)) {
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName("error");
      modelAndView.addObject("message", "错误：" + e.getMessage());
      return modelAndView;
    } else {
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
          .body(Response.instanceError(e.getCode()).withData(e.getErrorData()));
    }
  }

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public Object handleArgumentNotValid(MethodArgumentNotValidException e,
      HttpServletRequest request) {
    logger.warn("请求的参数错误 - {} : {}", e.getClass(), e.getMessage());
    if (userAgentAcceptsHtml(request)) {
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName("error");
      modelAndView.addObject("message", "请求参数错误：" + e.getMessage());
      return modelAndView;
    } else {
      return ResponseEntity.ok(Response.instanceFail(ErrorCode.INVALID_PARAMS)
          .withDataEntry("message", e.getMessage()));
    }
  }

  private static boolean userAgentAcceptsHtml(HttpServletRequest request) {
    final String acceptType = request.getHeader("Accept");
    return acceptType != null && acceptType.contains(MediaType.TEXT_HTML_VALUE);
  }

}
